﻿using System;
using System.Collections.Generic;

namespace Games.PegSolitaire
{
    class Game
    {
        public const byte LENGTH = 7;
        private byte[,] status;
        public int Count { get; private set; }
        public int Step { get; private set; }
        private int lastX, lastY;
        private Stack<(int, int, int, int, bool)> steps = new Stack<(int, int, int, int, bool)>();

        public void Init()
        {
            this.status = new byte[7, 7] {
                { 2, 2, 1, 1, 1, 2, 2 },
                { 2, 2, 1, 1, 1, 2, 2 },
                { 1, 1, 1, 1, 1, 1, 1 },
                { 1, 1, 1, 0, 1, 1, 1 },
                { 1, 1, 1, 1, 1, 1, 1 },
                { 2, 2, 1, 1, 1, 2, 2 },
                { 2, 2, 1, 1, 1, 2, 2 },
            };
            this.Count = 32;
            this.Step = 0;
            this.steps.Clear();
        }

        public bool Jump(int x, int y, int tox, int toy)
        {
            if(x < 0 || x > 6 || y < 0 || y > 6)
            {
                return false;
            }
            if(tox < 0 || tox > 6 || toy < 0 || toy > 6)
            {
                return false;
            }
            if(this.status[x, y] != 1)
            {
                return false;
            }
            if(this.status[tox, toy] != 0)
            {
                return false;
            }
            int dx = tox - x, dy = toy - y;
            if(dx * dy != 0)
            {
                return false;
            }
            if(Math.Abs(dx + dy) != 2)
            {
                return false;
            }

            if(this.status[tox, toy] != 0)
            {
                return false;
            }
            if(this.status[x + dx / 2, y + dy / 2] != 1)
            {
                return false;
            }
            var hasStep = lastX != x || lastY != y;
            if(hasStep)
            {
                this.Step++;
            }
            this.steps.Push((x, y, tox, toy, hasStep));
            this.status[x, y] = 0;
            this.status[tox, toy] = 1;
            this.status[x + dx / 2, y + dy / 2] = 0;
            lastX = tox;
            lastY = toy;
            this.Count--;
            return true;
        }

        public bool Back(out int x, out int y, out int tox, out int toy)
        {
            (x, y, tox, toy) = (0, 0, 0, 0);
            if(this.steps.Count == 0)
            {
                return false;
            }
            bool hs;
            (x, y, tox, toy, hs) = this.steps.Pop();
            int dx = tox - x, dy = toy - y;

            this.status[x, y] = 1;
            this.status[tox, toy] = 0;
            this.status[x + dx / 2, y + dy / 2] = 1;
            this.Count++;
            if(hs)
            {
                this.Step--;
            }
            if(this.steps.Count > 0)
            {
                (_, _, lastX, lastY, _) = this.steps.Peek();
            }
            else
            {
                (lastX, lastY) = (0, 0);
            }
            return true;
        }

        public bool CanMove()
        {
            if(Count == 1)
            {
                return false;
            }
            for(int i = 1; i < LENGTH - 1; i++)
            {
                for(int j = 0; j < LENGTH; j++)
                {
                    if(this.status[i, j] == 1)
                    {
                        if(this.status[i - 1, j] + this.status[i + 1, j] == 1)
                        {
                            return true;
                        }
                    }
                    if(this.status[j, i] == 1)
                    {
                        if(this.status[j, i - 1] + this.status[j, i + 1] == 1)
                        {
                            return true;
                        }
                    }
                }
            }
            return false;
        }

        public IEnumerable<(int, int, byte)> Deconstruct()
        {
            for(int i = 0; i < LENGTH; i++)
            {
                for(int j = 0; j < LENGTH; j++)
                {
                    var s = this.status[i, j];
                    if(s == 0 || s == 1)
                    {
                        yield return (i, j, s);
                    }
                }
            }
        }
    }
}
